package com.cfpamf.ms.insur.pay.facade.config;

import com.cfpamf.common.ms.result.Result;
import com.cfpamf.ms.insur.pay.facade.constant.PayConstant;
import com.cfpamf.ms.insur.pay.facade.util.SignUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.RuntimeJsonMappingException;
import feign.FeignException;
import feign.Response;
import feign.codec.Decoder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

/**
 * Create By zhengjing on 2019-10-21 15:02
 */
@Slf4j
@AllArgsConstructor
public class PayValidDecoder implements Decoder {

//    private Decoder decoder;

    private String key;

    private ObjectMapper objectMapper;

    /**
     * 验证签名 并解析成对象
     */
    @Override
    @SuppressWarnings("unchecked")
    public Object decode(Response response, Type type) throws IOException, FeignException {
        if (response.body() == null)
            return null;
        Reader reader = response.body().asReader();
        if (!reader.markSupported()) {
            reader = new BufferedReader(reader, 1);
        }
        Object decode;
        try {
            reader.mark(1);
            if (reader.read() == -1) {
                return null; // Eagerly returning null avoids "No content to map due to end-of-input"
            }
            reader.reset();
            decode = objectMapper.readValue(reader, objectMapper.constructType(type));
            if (decode instanceof Result) {// 只校验返回值为Result的数据
                boolean success = ((Result) decode).isSuccess();
                //z如果接口调用失败 也不校验
                Object data = ((Result) decode).getData();
                if (success && data != null) {
                    String signVal = getSingleHeader(response, PayConstant.HEADER_NAME_SIGN);
                    Map<String, Object> map = objectMapper.convertValue(data, Map.class);
                    SignUtil.validSign(map, signVal, key);
                    log.info("校验返回数据的签名成功：{}", signVal);
                }
            }
        } catch (RuntimeJsonMappingException e) {
            if (e.getCause() != null && e.getCause() instanceof IOException) {
                throw IOException.class.cast(e.getCause());
            }
            throw e;
        }
        return decode;
    }

    private static String getSingleHeader(Response response, String headName) {
        Collection<String> vals = response.headers().getOrDefault(headName, Collections.emptyList());
        if (vals == null || vals.isEmpty()) {
            return "";
        }
        return vals.iterator().next();
    }
}
